// List concept
// Copyright 2006 (C) Ralph Thomas

#ifndef MISSION_UTIL_CONCEPTS_LIST_H
#define MISSION_UTIL_CONCEPTS_LIST_H

#include <adobe/value.hpp>
#include <boost/shared_ptr.hpp>
#include <vector>

namespace util {
	//
	/// The concept namespace contains concepts that are used across Mission.
	/// A concept is like an interface, except that it doesn't have to be
	/// implemented in the typical C++ way. In theory a concept can be created
	/// from some instance that just has the same methods in it -- this is how
	/// the Adobe regular_object works. However we currently don't expose that
	/// functionality because we typically only need to create concepts from
	/// adobe::value_ts (which isn't possible with regular_object just yet, and
	/// won't be possible in full generality until something like ConceptC++
	/// gets adopted).
	//
	namespace concept {
		//
		/// The List concept defines the functions required for something to
		/// be considered a List.
		//
		struct ListInterface {
			virtual ~ListInterface();
			virtual std::size_t size() const = 0;
			virtual adobe::value_t at(unsigned int) const = 0;
			virtual bool empty() const = 0;
		};
		typedef boost::shared_ptr<ListInterface> ListInstance;
		struct List {
			ListInstance instance_m;
			
			List(const ListInstance& i) : instance_m(i) {}
			List(const List& rhs) : instance_m(rhs.instance_m) {}
			List() {}
			
			inline std::size_t size() const {
				if( instance_m ) return instance_m->size();
				return 0;
			}
			inline adobe::value_t at(unsigned int i) const {
				if( instance_m ) return instance_m->at(i);
				throw std::runtime_error( "out of range" );
			}
			inline bool empty() const {
				if( instance_m ) return instance_m->empty();
				return true;
			}
			inline bool operator==( const List& rhs ) const {
				return rhs.instance_m == instance_m;
			}
			inline List& operator=( const List& rhs ) {
				instance_m = rhs.instance_m;
				return *this;
			}
		};
		//
		/// The ListProxy template is used to make something implement
		/// the List concept when it's not related to ListInteface.
		//
		template<typename T>
		struct ListProxy : public ListInterface {
			T	target_m;
			
			ListProxy( const T& val ) : target_m(val) {}
			virtual ~ListProxy() {}
			virtual std::size_t size() const { return target_m.size(); }
			virtual adobe::value_t at(unsigned int i) const { return adobe::value_t(target_m[i]); }
			virtual bool empty() const { return target_m.empty(); }
		};
		//
		/// The ListProxyPtr template is used to make something implement
		/// the List concept when it's not related to ListInteface and is
		/// a pointer type.
		//
		template<typename T>
		struct ListProxyPtr : public ListInterface {
			T	target_m;
			
			ListProxyPtr( const T& val ) : target_m(val) {}
			virtual ~ListProxyPtr() {}
			virtual std::size_t size() const { return target_m->size(); }
			virtual adobe::value_t at(unsigned int i) const { return adobe::value_t((*target_m)[i]); }
			virtual bool empty() const { return target_m->empty(); }
		};
		//
		/// Attempt to get the List interface from the given value. If the
		/// type stored in the value does not meet the requirements of the
		/// List concept then null is returned.
		///
		/// \param	v	the value to extract a List concept from.
		/// \return	a List concept, or NULL if that concept is unavailable.
		//
		List get_list( const adobe::value_t& v );
	}
}

#endif
